#include "HelloWorldScene.h"

#define PTM_RATIO 32

USING_NS_CC;

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }
    
    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();


    /////////////////////////////
    // 2. add a menu item with "X" image, which is clicked to quit the program
    //    you may modify it.

    // add a "close" icon to exit the progress. it's an autorelease object
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback));
    
	pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
                                origin.y + pCloseItem->getContentSize().height/2));

    // create menu, it's an autorelease object
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition(CCPointZero);
    //this->addChild(pMenu, 1);

    /////////////////////////////
    // 3. add your codes below...

    // add a label shows "Hello World"
    // create and initialize a label
    
    CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
    
    // position the label on the center of the screen
    pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
                            origin.y + visibleSize.height - pLabel->getContentSize().height));

    // add the label as a child to this layer
    //this->addChild(pLabel, 1);


	/** My code start from here */
	winSize = CCDirector::sharedDirector()->getWinSize();

	gameObjList = CCArray::create();
	gameObjList->retain();

	map = CCTMXTiledMap::create("map_test_1.tmx");
	map->setAnchorPoint(ccp(0, 0));
	map->setPosition(ccp(0, 0));
	this->addChild(map);
	tileSize = map->getTileSize();

	hero = GameObjHero::create("Hero.png", ccp(winSize.width/2, 150));
	hero->sprite->setScale(1.5f);
	map->addChild(hero->sprite);
	gameObjList->addObject(hero);
	heroSize = hero->sprite->getContentSize();

	//GameObjEnemy *enemy = GameObjEnemy::create("shuimu.png", CCSizeMake(33, 33), ccp(winSize.width, 160), 2.0f, 1);
	//map->addChild(enemy->sprite);
	//enemy->sprite->setAnchorPoint(ccp(0.5f, 0.5f)); // TODO: Refactor
	//enemy->sprite->setScale(2.0f);
	//gameObjList->addObject(enemy);

	//GameObjEnemy *enemy2 = GameObjEnemy::create("shuimu.png", CCSizeMake(33, 33), ccp(winSize.width, 160), 1.5f, 2);
	//map->addChild(enemy2->sprite);
	//enemy2->sprite->setAnchorPoint(ccp(0.5f, 0.5f)); // TODO: Refactor
	//enemy2->sprite->setScale(1.5f);
	//gameObjList->addObject(enemy2);

	//GameObjEnemy *enemy3 = GameObjEnemy::create("shuimu.png", CCSizeMake(33, 33), ccp(winSize.width, 160), 1.0f, 3);
	//map->addChild(enemy3->sprite);
	//enemy3->sprite->setAnchorPoint(ccp(0.5f, 0.5f)); // TODO: Refactor
	//gameObjList->addObject(enemy3);

	//GameObjEnemy *enemy4 = GameObjEnemy::create("zy_body.png", CCSizeMake(65, 33), ccp(winSize.width, 160), 2.0f, 1);
	//enemy4->isFlight = false;
	//map->addChild(enemy4->sprite);
	//enemy4->sprite->setAnchorPoint(ccp(0.5f, 0)); // TODO: Refactor
	//gameObjList->addObject(enemy4);

	CCDirector::sharedDirector()->getKeypadDispatcher()->addDelegate(hero);

	scheduleUpdate(); 
    
    return true;
}

void HelloWorld::update(float delta){
	
	//updateHero();
	CCObject* pObject;
	GameObj *gameObj;
	CCARRAY_FOREACH(gameObjList, pObject){
		gameObj = dynamic_cast<GameObj*>(pObject);
		updateGameActObj(gameObj);
	}
	

}

void HelloWorld::updateGameActObj(GameObj *gameObj){

	// TODO: Need refactor
	if(gameObj->isFlight){
		if(gameObj->gameObjType == ENEMY){
			CCPoint pos = hero->getPosition();
			dynamic_cast<GameObjEnemy*>(gameObj)->updateTarget(hero);
		}
		return;
	}

	CCPoint gameObjPosition = gameObj->sprite->getPosition();
	const CCPoint mapPosition = map->getPosition();
	CCTMXLayer* groundLayer = map->layerNamed("Ground");
	CCDictionary *propertise;
	const CCString *contactVal;
	unsigned mvalue;

	float deltaX = (gameObj->rightMove - gameObj->leftMove) * gameObj->horiSpeed; 
	float deltaY = (gameObj->jumpMove) * gameObj->jumpSpeed + (gameObj->upMove - gameObj->downMove) * gameObj->vertSpeed;  // move from update	
	
	short indexX = (gameObjPosition.x) / tileSize.width;
	short indexY = map->getMapSize().height - ((gameObjPosition.y) / tileSize.height) - 1;
	CCPoint detectIndex = ccp(indexX, indexY);
	short tileGid = groundLayer->tileGIDAt(detectIndex);
	short tileGid2;

	//CCLog("indexX=%d   indexY=%d   gameObjPosition.x=%f   gameObjPosition.y=%f   deltaX=%f   deltaY=%f",  indexX, indexY, gameObjPosition.x, gameObjPosition.y, deltaX, deltaY);
	if(tileGid){
		propertise = map->propertiesForGID(tileGid);
		if(propertise){
			contactVal = propertise->valueForKey("Contact");
			if(contactVal){
				mvalue = contactVal->uintValue();

				gameObj->moveState = 0; // Clean gameObj's moving state first.
				gameObj->moveState |= (mvalue&TER_MASK); // Update gameObj's on terrain state.
				gameObj->moveState |= (mvalue&BLOCK_MASK); // Update gameObj's moving state for blocking.

				if((mvalue&TER_MASK) == TER_GROUND){ // gameObj is on ground.
					/** Pixel correction. */
					if(deltaY < 0){
						float fineCoordY = (map->getMapSize().height - indexY - 1) * tileSize.height;
						if((gameObjPosition.y + deltaY) < fineCoordY){
							deltaY = fineCoordY - gameObjPosition.y;
							gameObj->moveState |= TER_GROUND; // Set gameObj state is on ground.
							gameObj->jumpMove = 0;
						}
					}/** End pixel correction. */
				}

				if((mvalue&TER_MASK) == TER_AIR){ // gameObj is in air.
					gameObj->moveState |= TER_AIR; // Set gameObj state is in air.
				}

				if(mvalue & UP_BLOCK){ // gameObj can't go up any more.
					gameObj->jumpMove = -0.5f;
				}

				if(mvalue & DOWN_BLOCK){ // gameObj can't go down any more.
				}
		
			}
		}
	}

	gameObj->sprite->setPosition(ccp(gameObjPosition.x, gameObjPosition.y + deltaY)); // move from update

	gameObjPosition = gameObj->sprite->getPosition();
	indexX = (gameObjPosition.x) / tileSize.width;
	indexY = map->getMapSize().height - floor(((gameObjPosition.y) / tileSize.height)) - 1;
	detectIndex = ccp(indexX, indexY);
	tileGid2 = groundLayer->tileGIDAt(detectIndex);
	
	//CCLog("indexX=%d   indexY=%d   gameObjPosition.x=%f   gameObjPosition.y=%f   deltaX=%f   deltaY=%f",  indexX, indexY, gameObjPosition.x, gameObjPosition.y, deltaX, deltaY);
	//CCLog("");

	if(tileGid2){
		if(tileGid2 != tileGid){
			propertise = map->propertiesForGID(tileGid2);
		}
		if(propertise){
			if(tileGid2 != tileGid){
				contactVal = propertise->valueForKey("Contact");
			}
			if(contactVal){
				mvalue = contactVal->uintValue();

				gameObj->moveState |= (mvalue&BLOCK_MASK); // Update gameObj's moving state for blocking.

				//CCLog("gameObj->moveState=%d", gameObj->moveState);
				if((mvalue&RIGHT_BLOCK) && deltaX>0){ // gameObj can't go right any more.
					/** Pixel correction. */
					float fineCoordX = (indexX) * tileSize.width + tileSize.width/2;
					if((gameObjPosition.x + deltaX) > fineCoordX){
						deltaX = fineCoordX - gameObjPosition.x;
						deltaX = 0;
					}
					/** End pixel correction. */
				}

				if((mvalue&LEFT_BLOCK) && deltaX<0){ // gameObj can't go left any more.
					//CCLog("left block");
					/** Pixel correction. */
					float fineCoordX = (indexX) * tileSize.width + tileSize.width/2;
					if((gameObjPosition.x + deltaX) < fineCoordX){
						deltaX = fineCoordX - gameObjPosition.x;
						deltaX = 0;
					}
					/** End pixel correction. */
				}

			}

		}
	}

	gameObj->sprite->setPosition(ccp(gameObjPosition.x + deltaX, gameObjPosition.y)); // move from update


	/** If map horizon position is 0 and if gameObj go left, then move gameObj. 
		If map horizon position is (tileMap.width - win.width) and if gameObj go right, then move gameObj.
		If gameObj's (position.x < winMapCenterPoint.x) and if gameObj go right, then move gameObj.
		If gameObj's (position.x > winMapCenterPoint.x) and if gameObj go left, then move gameObj.*/
	if(gameObj->gameObjType == HERO){
		map->setPosition(ccp(mapPosition.x, mapPosition.y - deltaY));
		if((mapPosition.x >= 0 && deltaX < 0) 
			|| (mapPosition.x == (winSize.width - map->getMapSize().width*tileSize.width) && deltaX > 0)
			|| (gameObj->sprite->getPosition().x < winSize.width/2 && deltaX > 0)
			|| ((gameObj->sprite->getPosition().x > (map->getMapSize().width*tileSize.width - winSize.width/2)) && deltaX < 0)){
		}else{
			map->setPosition(ccp(mapPosition.x - deltaX, mapPosition.y - deltaY));
		} // move from update
	}

	if(gameObj->gameObjType == ENEMY){
		CCPoint pos = hero->getPosition();
		dynamic_cast<GameObjEnemy*>(gameObj)->updateTarget(hero);
	}
	


	if(gameObj->jumpMove > 0)
 		gameObj->moveState |= TER_AIR;

	if(gameObj->moveState & TER_AIR){
		gameObj->jumpMove -= 0.2;
		
		if(gameObj->jumpMove < MAX_VERT_SPEED)
			gameObj->jumpMove = MAX_VERT_SPEED;
	}

}

//void HelloWorld::updateHero(){
//	heroPosition = hero->sprite->getPosition();
//	mapPosition = map->getPosition();
//	CCTMXLayer* groundLayer = map->layerNamed("Ground");
//	CCDictionary *propertise;
//	const CCString *contactVal;
//
//
//	deltaX = (hero->rightMove - hero->leftMove) * hero->horiSpeed; 
//	deltaY = (hero->jumpMove) * hero->jumpSpeed + (hero->upMove - hero->downMove) * hero->vertSpeed;  // move from update	
//	
//	indexX = (heroPosition.x) / tileSize.width;
//	indexY = map->getMapSize().height - ((heroPosition.y) / tileSize.height) - 1;
//	detectIndex = ccp(indexX, indexY);
//	tileGid = groundLayer->tileGIDAt(detectIndex);
//
//	//CCLog("indexX=%d   indexY=%d   heroPosition.x=%f   heroPosition.y=%f   deltaX=%f   deltaY=%f",  indexX, indexY, heroPosition.x, heroPosition.y, deltaX, deltaY);
//	if(tileGid){
//		propertise = map->propertiesForGID(tileGid);
//		if(propertise){
//			contactVal = propertise->valueForKey("Contact");
//			if(contactVal){
//				mvalue = contactVal->uintValue();
//
//				hero->moveState = 0; // Clean hero's moving state first.
//				hero->moveState |= (mvalue&TER_MASK); // Update hero's on terrain state.
//				hero->moveState |= (mvalue&BLOCK_MASK); // Update hero's moving state for blocking.
//
//				if((mvalue&TER_MASK) == TER_GROUND){ // Hero is on ground.
//					/** Pixel correction. */
//					if(deltaY < 0){
//						float fineCoordY = (map->getMapSize().height - indexY - 1) * tileSize.height;
//						if((heroPosition.y + deltaY) < fineCoordY){
//							deltaY = fineCoordY - heroPosition.y;
//							hero->moveState |= TER_GROUND; // Set hero state is on ground.
//							hero->jumpMove = 0;
//						}
//					}/** End pixel correction. */
//				}
//
//				if((mvalue&TER_MASK) == TER_AIR){ // Hero is in air.
//					hero->moveState |= TER_AIR; // Set hero state is in air.
//				}
//
//				if(mvalue & UP_BLOCK){ // Hero can't go up any more.
//					hero->jumpMove = -0.5f;
//				}
//
//				if(mvalue & DOWN_BLOCK){ // Hero can't go down any more.
//				}
//		
//			}
//		}
//	}
//
//	hero->sprite->setPosition(ccp(heroPosition.x, heroPosition.y + deltaY)); // move from update
//
//	heroPosition = hero->sprite->getPosition();
//	indexX = (heroPosition.x) / tileSize.width;
//	indexY = map->getMapSize().height - floor(((heroPosition.y) / tileSize.height)) - 1;
//	detectIndex = ccp(indexX, indexY);
//	tileGid2 = groundLayer->tileGIDAt(detectIndex);
//	
//	//CCLog("indexX=%d   indexY=%d   heroPosition.x=%f   heroPosition.y=%f   deltaX=%f   deltaY=%f",  indexX, indexY, heroPosition.x, heroPosition.y, deltaX, deltaY);
//	//CCLog("");
//
//	if(tileGid2){
//		if(tileGid2 != tileGid){
//			propertise = map->propertiesForGID(tileGid2);
//		}
//		if(propertise){
//			if(tileGid2 != tileGid){
//				contactVal = propertise->valueForKey("Contact");
//			}
//			if(contactVal){
//				mvalue = contactVal->uintValue();
//
//				hero->moveState |= (mvalue&BLOCK_MASK); // Update hero's moving state for blocking.
//
//				//CCLog("hero->moveState=%d", hero->moveState);
//				if((mvalue&RIGHT_BLOCK) && deltaX>0){ // Hero can't go right any more.
//					/** Pixel correction. */
//					float fineCoordX = (indexX) * tileSize.width + tileSize.width/2;
//					if((heroPosition.x + deltaX) > fineCoordX){
//						deltaX = fineCoordX - heroPosition.x;
//						deltaX = 0;
//					}
//					/** End pixel correction. */
//				}
//
//				if((mvalue&LEFT_BLOCK) && deltaX<0){ // Hero can't go left any more.
//					//CCLog("left block");
//					/** Pixel correction. */
//					float fineCoordX = (indexX) * tileSize.width + tileSize.width/2;
//					if((heroPosition.x + deltaX) < fineCoordX){
//						deltaX = fineCoordX - heroPosition.x;
//						deltaX = 0;
//					}
//					/** End pixel correction. */
//				}
//
//			}
//
//		}
//	}
//
//	hero->sprite->setPosition(ccp(heroPosition.x + deltaX, heroPosition.y)); // move from update
//
//
//	/** If map horizon position is 0 and if hero go left, then move hero. 
//		If map horizon position is (tileMap.width - win.width) and if hero go right, then move hero.
//		If hero's (position.x < winMapCenterPoint.x) and if hero go right, then move hero.
//		If hero's (position.x > winMapCenterPoint.x) and if hero go left, then move hero.*/
//	map->setPosition(ccp(mapPosition.x, mapPosition.y - deltaY));
//	if((mapPosition.x >= 0 && deltaX < 0) 
//		|| (mapPosition.x == (winSize.width - map->getMapSize().width*tileSize.width) && deltaX > 0)
//		|| (hero->sprite->getPosition().x < winSize.width/2 && deltaX > 0)
//		|| ((hero->sprite->getPosition().x > (map->getMapSize().width*tileSize.width - winSize.width/2)) && deltaX < 0)){
//	}else{
//		map->setPosition(ccp(mapPosition.x - deltaX, mapPosition.y - deltaY));
//	} // move from update
//
//
//	if(hero->jumpMove > 0)
// 		hero->moveState |= TER_AIR;
//
//	if(hero->moveState & TER_AIR){
//		hero->jumpMove -= 0.2;
//		
//		if(hero->jumpMove < MAX_VERT_SPEED)
//			hero->jumpMove = MAX_VERT_SPEED;
//	}
//
//}


void HelloWorld::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
	CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
    CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
#endif
}
